package etr.bk.db;

import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JProgressBar;

import etr.bk.gui.MainListener;

public class WorkDBImage {

	private Connection conn = null;
	
	private GetTask taskGet = null;
	private SetTask taskSet = null;
	private UnloadTask taskUnload = null;
	private boolean flagForProgress = false;
	
	public WorkDBImage(Connection con){
		this.conn = con;
	}
	
	
	public BufferedImage getImage(Integer id){
		
		PreparedStatement pstat = null;
		ResultSet rs = null;
		Blob blobobj = null;
		InputStream blobInpStream = null;
		BufferedImage img = null;
		
		String selectImage = "SELECT b.oBJ  FROM BLOBTABL b WHERE ID = ?";
		
		try {
			
			blobobj = this.conn.createBlob();
			
			pstat = this.conn.prepareStatement(selectImage);
			pstat.setInt(1, id);
			rs = pstat.executeQuery();
			
			if (rs.next())
			{
				blobobj = rs.getBlob(1);
			}
			else
			{
				System.out.println("Image whis id = " + id + " -- not exists (in WorkDBImage)");
				return null;
			}
			
			blobInpStream = blobobj.getBinaryStream();
			img = ImageIO.read(blobInpStream);
			
			return img;
			
		}
		catch (SQLException e) {
			e.printStackTrace();
		} 
		catch (IOException e) {
			e.printStackTrace();
		}
		finally {
			try {
				rs.close();
				pstat.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		return null;
	}
	
	public void delImage(Integer id){
		
		PreparedStatement pstat = null;
		String deleteImage = "DELETE FROM BLOBTABL WHERE ID = ?";
		
		try {
			pstat = this.conn.prepareStatement(deleteImage);
			pstat.setInt(1, id);
			pstat.executeUpdate();
			pstat.close();
		}
		catch (SQLException e) {
			e.printStackTrace();
		}
		
	}
	
	
	public ArrayList<WrapperFotoPan> getImages(Integer id, JProgressBar prgrBar){
		
		System.out.println("GetImages start");
		ArrayList<WrapperFotoPan> rezList = null;
		
		//---cancel previous thread-------------
		if (taskGet != null && !taskGet.isDone()){
			taskGet.cancel(true);
			System.out.println("+++++++++++++++++++++++");
			taskGet = null;
			prgrBar.setValue(0);
		}
		//---------------------------------------
		
		GetPictureTabClass getImgCls = new GetPictureTabClass();
		getImgCls.setId(id);
		getImgCls.setProgressBar(prgrBar);
		
		int amount = 0;
		
		//----------How many tuples-------------------
		
		try {
			PreparedStatement pstat = conn.prepareStatement("SELECT count(*)  FROM BLOBTABL WHERE USID = ?");
			pstat.setInt(1, id);
			ResultSet rs = pstat.executeQuery();
			if (rs.next()){
				amount = rs.getInt(1);
				if (rs.wasNull()) return null;
			}
			else return null;
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
		System.out.println("# of tuples == " +amount);
		
		//--------------------------------------------
		
		prgrBar.setMaximum(amount);
		
		this.taskGet = new GetTask(getImgCls); //new FutureTask<ArrayList<WrapperFotoPan>>(getImgCls);
		
		Thread t = new Thread(taskGet);
		t.start();
		
		System.out.println("Start select thread");
		
		return null;
	}
	
	public void setImages(Integer id, File [] filList, JProgressBar pgrsBar){
		
		SetPictureTabClass setImgCls = new SetPictureTabClass();
		setImgCls.setId(id);
		setImgCls.setTarList(filList);
		setImgCls.setProgressBar(pgrsBar);
		
		pgrsBar.setMaximum(filList.length);
		
		this.taskSet = new SetTask(setImgCls); //new FutureTask<Integer>(setImgCls);
		
		Thread t = new Thread(taskSet);
		t.start();
	}
	
	public void unloadImages(Integer ident, File tarDir, JProgressBar pgrsBar){
		System.out.println("Call unloadImages");
		
		UnloadImageClass unlImgCls = new UnloadImageClass();
		unlImgCls.setId(ident);
		unlImgCls.setProgressBar(pgrsBar);
		unlImgCls.setDirectory(tarDir);
		
		pgrsBar.setValue(0);
		
		int amount = 0;
		String selectForUnload = null;
		//----------How many tuples-------------------
		if (ident == null){
			selectForUnload = "SELECT count(*) FROM BLOBTABL";
		}
		else {
			selectForUnload = "SELECT count(*) FROM BLOBTABL b WHERE (ID = SELECT BID FROM US WHERE ID = ?) OR b.USID = ?";
		}
		
		try {
			PreparedStatement pstat = conn.prepareStatement(selectForUnload);
			if (ident != null){
				pstat.setInt(1, ident);
				pstat.setInt(2, ident);
			}
			ResultSet rs = pstat.executeQuery();
			if (rs.next()){
				amount = rs.getInt(1);
				if (rs.wasNull()) return;
			}
			else return;
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
		System.out.println("# of tuples == " +amount);

		pgrsBar.setMaximum(amount);
		//-------------------------------------------------
		
		this.taskUnload = new UnloadTask(unlImgCls);
		
		Thread t = new Thread(taskUnload);
		t.start();
		
		System.out.println("Start UNLOAD thread");
	}
	
	public void interruptUnload(){
		if (taskUnload != null && !taskUnload.isDone()){
			taskUnload.cancel(true);
			taskUnload = null;
		}
	}
	
	//-----------Cancel for mListener (on close main Window)------
	
	public void cancelAllThreads(){
		this.interruptUnload();
		
		if (taskGet != null && !taskGet.isDone()){
			taskGet.cancel(true);
		}
		
		if (taskSet != null && !taskSet.isDone()){
			taskSet.cancel(true);
		}
	}
	
	//-----------Inner class for Picture - thread----------
	
	
 	private class GetPictureTabClass implements Callable<ArrayList<WrapperFotoPan>> {

		private Connection conn = null;
		private Integer id = null;
		private JProgressBar progressBar;
		private int counter;

		public GetPictureTabClass(){
			this.conn = WorkDBImage.this.conn;
		}
		
		public void setId(Integer id) {
			this.id = id;
		}
			
		public void setProgressBar(JProgressBar progressBar) {
			this.progressBar = progressBar;
		}

		public ArrayList<WrapperFotoPan> call() throws Exception {
			
			ArrayList<WrapperFotoPan> rezList = new ArrayList<WrapperFotoPan>();
			
			WrapperFotoPan wrapper = null;
			
			PreparedStatement pstat = null;
			ResultSet resSet = null;
			InputStream blobInpStream = null;
			BufferedImage img = null;
			Image image = null;
			Blob blobobj = null;
			int fotoID = 0;
			
			
			String statement = "SELECT ID, SMLOBJ FROM BLOBTABL WHERE USID = ?";
			
			WorkDBImage.this.flagForProgress = false;
			
			pstat = this.conn.prepareStatement(statement);
			pstat.setInt(1, id);
			resSet = pstat.executeQuery();
			
			while (resSet.next())
			{
				if (Thread.currentThread().isInterrupted()){
					System.out.println("@@@@HEY&&&&&&-Interrupt");
					return null;
				}
				
				fotoID = resSet.getInt(1);
				blobobj = resSet.getBlob(2);
				
				if (resSet.wasNull() != true)
				{
					blobInpStream = blobobj.getBinaryStream();
					img = ImageIO.read(blobInpStream);
					blobInpStream.close();
					blobInpStream = null;
					blobobj.free();
					blobobj = null;

					// create preview ----
					image = img.getScaledInstance(160, 160, Image.SCALE_DEFAULT);
					img = null;
					
					wrapper = new WrapperFotoPan(fotoID, image);
					image = null;
					
					//System.out.println(image.toString()+" "+image.getHeight(null));
					
					
					if (!WorkDBImage.this.flagForProgress){
						EventQueue.invokeLater(new
								Runnable() {
									public void run() {
										GetPictureTabClass.this.progressBar.setValue(++counter);
									}
								});
					}
					//--------------------
				}
				else wrapper = null;
				
				if(wrapper != null){
					rezList.add(wrapper);
				}	

				wrapper = null;
			}
			
			System.out.println("Counter - "+counter);
			System.gc();
			resSet.close();
			pstat.close();
			
			Thread.currentThread();
			Thread.sleep(500);
			
			return rezList;
		}
	}
	
	private class SetPictureTabClass implements Callable<Integer>{

		private Connection conn = null;
		private Integer id = null;
		private ArrayList<BufferedImage> tarList = null;
		private File [] files = null;
		private JProgressBar progressBar;
		private int counter;
		
		

		public SetPictureTabClass(){
			this.conn = WorkDBImage.this.conn;
		}
		
		public void setProgressBar(JProgressBar progressBar) {
			this.progressBar = progressBar;
		}
		
		public void setId(Integer id) {
			this.id = id;
		}

		public void setTarList(File [] files) {
			this.files = files;
		}

		public Integer call() throws Exception {
			
			PreparedStatement pstat = null;
			String sql = "INSERT INTO BLOBTABL (OBJ, USID, SMLOBJ) VALUES (?,?,?)";
			BufferedImage img = null;
			OutputStream strm = null;
			Blob blbob = null;
			Blob blbobPrev = null;
			int bufImgType = 0;
			Image image = null;
			
			WorkDBImage.this.flagForProgress = true;
			
			this.counter = 0;
			
			blbob = conn.createBlob();
			blbobPrev = conn.createBlob();
			
			conn.setAutoCommit(false);
			
			pstat = conn.prepareStatement(sql);
			
			for(File fil: this.files){
				
				strm = blbob.setBinaryStream(1);
				img = ImageIO.read(new FileInputStream(fil));
				ImageIO.write(img, "jpg", strm);
				
				strm.flush();
				strm.close();
				
				//-----------Create preview----------
				strm = blbobPrev.setBinaryStream(1);
				
				bufImgType = img.getType();
				image = img.getScaledInstance(160, 160, Image.SCALE_DEFAULT);
				img = new BufferedImage(160, 160, bufImgType);
				Graphics2D g2 = img.createGraphics();
				g2.drawImage(image,null,null);
				g2.dispose();
				
				ImageIO.write(img, "jpg", strm);
				//------------------------------------
				
				strm.flush();
				strm.close();
			
				pstat.setBlob(1, blbob);
				pstat.setInt(2, this.id);
				pstat.setBlob(3, blbobPrev);
			
				pstat.executeUpdate();
			
				blbob.free();
				blbobPrev.free();
				blbob = conn.createBlob();
				blbobPrev = conn.createBlob();
				
				if (WorkDBImage.this.flagForProgress){
					EventQueue.invokeLater(new Runnable() {
					
						public void run() {
							SetPictureTabClass.this.progressBar.setValue(++counter);
						}
					});
				}
				
				System.out.println("Insert into DB in thread");
			
			}
			
			conn.commit();
			conn.setAutoCommit(true);
			
			pstat.close();
			
			Thread.currentThread();
			Thread.sleep(500);
			
			return this.id;
		}
	}
	
	private class UnloadImageClass implements Callable<Boolean>{

		private Connection conn;
		private Integer id = null;
		private JProgressBar progressBar;
		private File directory;
		private int counter;
		
		public UnloadImageClass(){
			this.conn = WorkDBImage.this.conn;
			this.counter = 0;
		}
		
		public void setProgressBar(JProgressBar progress){
			this.progressBar = progress;
		}
		
		public void setId(Integer ident){
			this.id = ident;
		}
		
		public void setDirectory(File fil){
			this.directory = fil;
		}
		
		private void exportBuffImageIntoFile(BufferedImage image, Integer nameInt){
			//System.out.println("Call exportBuffImageIntoFile");
			String filName = this.directory.toString()+"/"+nameInt.toString()+".jpg";
			File fil = new File(filName);
			
			try {
				ImageIO.write(image, "jpg",fil);
				fil.createNewFile();
			}
			catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		public Boolean call() throws Exception {

			PreparedStatement pstat = null;
			ResultSet resSet = null;
			Blob blobobj = null;
			
			InputStream blobInpStream = null;
			BufferedImage img = null;
			
			Integer imageName = null;
			String selectForUnload = null;
			
			if (id == null){
				selectForUnload = "SELECT obj, id FROM BLOBTABL";
			}
			else {
				selectForUnload = "SELECT obj, id FROM BLOBTABL b WHERE (ID = SELECT BID FROM US WHERE ID = ?) OR b.USID = ?";
			}
			
			pstat = conn.prepareStatement(selectForUnload);
			if (id != null) {
				pstat.setInt(1, id);
				pstat.setInt(2, id);
			}
			resSet = pstat.executeQuery();
			
			while(resSet.next()){
				counter++;
				
				if (Thread.currentThread().isInterrupted()){
					System.out.println("@@@@HEY&&&&&&-Interrupt");
					counter = 0;
					return null;
				}
				
				blobobj = resSet.getBlob(1);
				
				if (!resSet.wasNull()){
					
					imageName = resSet.getInt(2);
					
					blobInpStream = blobobj.getBinaryStream();
					img = ImageIO.read(blobInpStream);
					blobInpStream.close();
					blobInpStream = null;
					blobobj.free();
					blobobj = null;
					
					this.exportBuffImageIntoFile(img, imageName);
					
					EventQueue.invokeLater(new
							Runnable() {
								public void run() {
									UnloadImageClass.this.progressBar.setValue(counter);
								}
							});
				}
			}
			
			System.gc();
			resSet.close();
			pstat.close();
			
			Thread.currentThread();
			Thread.sleep(500);
			
			return true;
		}
		
	}
	
	//---------FOR show END Objects--------------------
	
	private class SetTask extends FutureTask<Integer>{

		public SetTask(Callable<Integer> arg0) {
			super(arg0);
		}
		
		public void done()
		{
			System.out.println("FutureTask -- setImages is done");
			try {
				
				MainListener.getListener().finishSetImage(this.get());
				
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	private class GetTask extends FutureTask<ArrayList<WrapperFotoPan>>{

		public GetTask(Callable<ArrayList<WrapperFotoPan>> arg0) {
			super(arg0);
		}
		
		public void done()
		{
		
				if (!this.isCancelled()&& this.isDone()){
					
					EventQueue.invokeLater(new Runnable() {
						public void run() {
							try {
								MainListener.getListener().finishGetImage(GetTask.this.get());
							}
							catch (InterruptedException e) {	
								e.printStackTrace();
							}
							catch (ExecutionException e) {
								e.printStackTrace();
							}
							catch (CancellationException i){
								System.out.println("NU   WE DONT NEED REZULT)))))");
							}
						}
					});
				}
		}
	}
	
	private class UnloadTask extends FutureTask<Boolean>{

		public UnloadTask(Callable<Boolean> arg0) {
			super(arg0);
		}
		
		public void done(){
			try {
				Thread.currentThread();
				Thread.sleep(1);
				System.out.println("Allle blya!!!!!!");
			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
			MainListener.getListener().finishUnloadImages(true);
		}
		
	}

}
